/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import {
  BaseCommand,
  CENTEREVENTS,
  CSPolygon,
  CSys,
  CadScene,
  CommandHint,
  CommandHintStatus,
  EventsRes,
  MathTool,
  SceneGraph,
  useStore,
} from '@amcax/base';
import { eventCenterManager } from '@app-base/common/events/EventCenterManager';
import { KEYBOARD_KEY } from '@app-cad/common/Constants';
import { ctx2 } from '@app-cad/module';
import { wsApi } from '@app-cad/server';
import i18n from 'i18next';
import { useEffect, useState } from 'react';
import useStateRef from 'react-usestateref';
import { Vector3 } from 'three-legacy';

// 草图 - 多边形
enum State {
  NONE,
  DRAW,
  FINISH,
}

type MouseState = State.NONE | State.DRAW | State.FINISH;

interface TrackingData {
  polygon: CSPolygon;
  vertexs: Vector3[];
}

interface PolygonCommandProps {
  title: string;
  onClose: () => void;
}

function PolygonCommand({ onClose }: PolygonCommandProps) {
  const updateCmdHighlightId = useStore((state) => state.updateCmdHighlightId);
  const [hits, setHits] = useState<string>('');
  const cadScene = ctx2.cadScene as CadScene;
  const sceneSetup = ctx2.viewer.sceneSetup;
  const assisGroup = cadScene.assisGroup;
  const xAxis = new Vector3(1, 0, 0);
  const yAxis = new Vector3(0, 1, 0);
  const zAxis = new Vector3(0, 0, 1);
  // 默认为 XOY 平面
  let faceCSys: CSys = MathTool.createCsysFromPlacement([
    [0, 0, 0],
    [0, 0, 1],
    [1, 0, 0],
  ]);
  const [planeName, setPlaneName, planeNameRef] = useStateRef('XOY');
  let planeNormal: Vector3 = new Vector3(0, 0, 1);
  let planeOrigin: Vector3 = new Vector3(0, 0, 0);
  let startPoint: Vector3; // 矩形起点
  let endPoint: Vector3; // 矩形终点

  let currentStatus: MouseState = State.NONE; // 记录当前状态

  const trackingData: TrackingData = {
    polygon: null,
    vertexs: [],
  };

  useEffect(() => {
    init();
    return onDestroy;
  }, []);

  const init = () => {
    setHits(
      '点击确定起点，当前绘制平面为 ' +
        planeName +
        ' 平面，按方向键切换绘制平面',
    );
    registerEvents();
  };
  const onDestroy = () => {
    unregisterEvents();
    releaseObjects();
    onClose();
  };

  // ========= 鼠标和键盘事件=========
  const registerEvents = () => {
    eventCenterManager.activeEventCenter
      .setState('polygon')
      .on(CENTEREVENTS.POINTERMOVE, onMouseMove)
      .on(CENTEREVENTS.POINTERUP, onMouseClick)
      .on(CENTEREVENTS.KEYUP, onKeyup)
      .addExit(onDestroy);
  };
  const unregisterEvents = () => {
    eventCenterManager.activeEventCenter
      .off(CENTEREVENTS.POINTERMOVE, onMouseMove)
      .off(CENTEREVENTS.POINTERUP, onMouseClick)
      .off(CENTEREVENTS.KEYUP, onKeyup)
      .setDefault();
  };

  const onKeyup = (e: EventsRes<KeyboardEvent>) => {
    if (e.key === KEYBOARD_KEY.ESC) {
      onDestroy();
    } else if (e.key === KEYBOARD_KEY.ENTER) {
      if (currentStatus === State.DRAW) {
        finishDraw();
        onDestroy();
      }
    } else if (e.key === KEYBOARD_KEY.ARROWUP) {
      changePlaneToXOY();
    } else if (e.key === KEYBOARD_KEY.ARROWRIGHT) {
      changePlaneToYOZ();
    } else if (e.key === KEYBOARD_KEY.ARROWLEFT) {
      changePlaneToXOZ();
    } else if (e.key === KEYBOARD_KEY.ARROWDOWN) {
      changePlaneToXOY();
    }
  };
  const onMouseClick = (e: EventsRes) => {
    if (e.button.onLeft) {
      if (currentStatus === State.NONE) {
        trackingData.polygon = null;
        // 鼠标左键，开始绘制
        startPoint = sceneSetup.mouseOnPlane(
          e.mouse.x,
          e.mouse.y,
          planeNormal,
          planeOrigin,
        );
        currentStatus = State.DRAW;
        // preview()
      } else if (currentStatus === State.DRAW) {
        currentStatus = State.FINISH;
        // 鼠标右键，完成
        finishDraw();
        onDestroy();
      }
    } else if (e.button.onRight) {
      currentStatus = State.FINISH;
      // 鼠标右键，放弃
      onDestroy();
    }
  };
  const onMouseMove = (e: EventsRes) => {
    // 在面上画圆形
    // const hits = e.hits;
    // if (hits[0]?.face) {
    //   planeOrigin = hits[0].point;
    //   const faceObj = hits[0].face.getMBrepFace()
    //   const tringleVer = faceObj.brepFace.data.tessellation.data[0][0]
    //   const a = new Vector3().fromArray(tringleVer[0])
    //     , b = new Vector3().fromArray(tringleVer[1])
    //     , c = new Vector3().fromArray(tringleVer[2])
    //   const ab = b.clone().sub(a.clone())
    //   const ac = c.clone().sub(a.clone())
    //   let nor = ab.cross(ac).normalize()
    //   planeNormal = nor
    //   faceCSys = faceObj.csys
    // }
    // startPoint?.clone().x ? faceCSys.origin = new Vector(startPoint.clone().x, startPoint.clone().y, startPoint.clone().z) : ''
    if (currentStatus === State.DRAW) {
      endPoint = sceneSetup.mouseOnPlane(
        e.mouse.x,
        e.mouse.y,
        planeNormal,
        planeOrigin,
      );
      preview();
    }
  };
  // ========= 鼠标和键盘事件 =========
  // ========= 位置变换 =========
  const changePlaneToXOY = () => {
    changePlane(zAxis, 'XOY');
  };
  const changePlaneToYOZ = () => {
    changePlane(xAxis, 'YOZ');
  };
  const changePlaneToXOZ = () => {
    changePlane(yAxis, 'XOZ');
  };
  const changePlane = (axis: Vector3, type: string) => {
    planeNormal = axis.clone();
    setPlaneName(type);
    planeOrigin = startPoint ? startPoint.clone() : planeNormal.clone();
    let _xAxis = []; // 局部坐标系的X轴
    let _zAxis = []; // 局部坐标系的Z轴
    if (type === 'XOY') {
      _xAxis = [1, 0, 0];
      // planeOrigin.z = 0
      _zAxis = zAxis.clone().toArray();
    } else if (type === 'YOZ') {
      _xAxis = [0, 0, 1];
      // planeOrigin.x = 0
      _zAxis = xAxis.clone().toArray();
    } else if (type === 'XOZ') {
      _xAxis = [1, 0, 0];
      // planeOrigin.y = 0
      _zAxis = yAxis.clone().toArray();
    }
    // const placement = [planeOrigin.clone().toArray(), axis.clone().toArray(), _xAxis]
    const placement = [planeOrigin.clone().toArray(), _zAxis, _xAxis];
    faceCSys = MathTool.createCsysFromPlacement(placement);
    if (trackingData.polygon) {
      trackingData.polygon && trackingData.polygon.resetCsys(faceCSys);
      preview();
    }
    setHits(
      '点击确定起点，当前绘制平面为 ' + type + ' 平面，按方向键切换绘制平面',
    );
  };
  // ========= 位置变换 =========

  const finishDraw = async () => {
    if (trackingData.polygon != null) {
      await wsApi.createPolygon(trackingData.vertexs);
    }
  };

  // 释放对象
  const releaseObjects = () => {
    trackingData.polygon && trackingData.polygon.destroy();

    assisGroup.clear();
    SceneGraph.emptyGroup(assisGroup);
    ctx2.viewer.requestRender();

    updateCmdHighlightId('');
  };

  const preview = () => {
    if (currentStatus === State.DRAW) {
      if (planeNameRef.current === 'XOY') {
        trackingData.vertexs = [
          new Vector3(startPoint.x, startPoint.y, startPoint.z),
          new Vector3(startPoint.x, endPoint.y, endPoint.z),
          new Vector3(endPoint.x, endPoint.y, endPoint.z),
          new Vector3(endPoint.x, startPoint.y, startPoint.z),
          new Vector3(startPoint.x, startPoint.y, startPoint.z),
        ];
      } else if (planeNameRef.current === 'YOZ') {
        trackingData.vertexs = [
          new Vector3(startPoint.x, startPoint.y, startPoint.z),
          new Vector3(startPoint.x, startPoint.y, endPoint.z),
          new Vector3(endPoint.x, endPoint.y, endPoint.z),
          new Vector3(endPoint.x, endPoint.y, startPoint.z),
          new Vector3(startPoint.x, startPoint.y, startPoint.z),
        ];
      } else if (planeNameRef.current === 'XOZ') {
        trackingData.vertexs = [
          new Vector3(startPoint.x, startPoint.y, startPoint.z),
          new Vector3(startPoint.x, startPoint.y, endPoint.z),
          new Vector3(endPoint.x, endPoint.y, endPoint.z),
          new Vector3(endPoint.x, endPoint.y, startPoint.z),
          new Vector3(startPoint.x, startPoint.y, startPoint.z),
        ];
      }
      // 绘制矩形
      if (!trackingData.polygon) {
        trackingData.polygon = new CSPolygon({
          vertexs: trackingData.vertexs,
          csys: faceCSys,
          lineWidth: 2,
        });
        // trackingData.polygon.showPoints()
        trackingData.polygon.addTo(assisGroup);
      } else {
        // trackingData.polygon.showPoints()
        trackingData.polygon.update({ vertexs: trackingData.vertexs });
        // trackingData.polygon.setVertexs(trackingData.vertexs)
      }

      // // draw input label
      // let labelText = startPoint.distanceTo(endPoint)
      // let labelPos = new Vector3()
      // labelPos.x = (startPoint.x + endPoint.x) / 2
      // labelPos.y = (startPoint.y + endPoint.y) / 2
      // labelPos.z = (startPoint.z + endPoint.z) / 2
      // if (!trackingData.rLabel) {
      //   trackingData.rLabel = new css2dInputLable({ text: labelText, position: labelPos })
      //   trackingData.rLabel.focus()
      //   trackingData.rLabel.addTo(assisGroup)
      // } else {
      //   trackingData.rLabel.update(labelText, labelPos)
      // }
      ctx2.viewer.requestRender();
    }
  };
  return (
    <CommandHint
      status={CommandHintStatus.INFO}
      content={hits}
    />
  );
}

export const cmdPolygon: BaseCommand = {
  id: 'CmdPolygon',
  label: 'command.polygon',
  icon: 'commands/feature/polygon',
  create: (label: string, onClose: () => void) => (
    <PolygonCommand
      title={i18n.t(label)}
      onClose={onClose}
    />
  ),
};
